﻿using Stateless;
using System;
using System.Collections.Generic;

namespace StatelessDemo
{
    /// <summary>
    /// 接口定义了自动售货机的基本操作。
    /// </summary>
    public interface IVendingMachine
    {
        void InsertCoin(); // 插入硬币
        void EjectCoin(); // 退币
        void Dispense(); // 出货
        void Refill(); // 补货
    }

    /// <summary>
    /// 实现了自动售货机的状态管理及行为。
    /// </summary>
    public class VendingMachine : IVendingMachine
    {
        /**
         * 定义了一个表示自动售货机状态的枚举。
         * 这个枚举用于表示售货机在不同情况下的状态，例如：
         * - Idle：空闲状态，没有进行任何操作。
         * - HasCoin：已有硬币投入，等待用户选择商品。
         * - Dispensing：正在分发商品。
         * - OutOfStock：商品缺货。
         */
        public enum States { Idle, HasCoin, Dispensing, OutOfStock }

        /**
         * 定义自动售货机操作的触发事件
         */
        public enum Triggers { 
            InsertCoin, // 插入硬币
            EjectCoin,  // 弹出硬币
            Dispense,   // 分发商品
            Refill      // 补充商品
        }


        // 使用StateMachine来管理状态。
        private readonly StateMachine<States, Triggers> _machine;
        // 状态对应的消息，用于用户界面显示。
        private readonly Dictionary<States, string> _stateMessages = new Dictionary<States, string>
        {
            { States.Idle, "空闲中"},
            { States.HasCoin, "已接收硬币"},
            { States.Dispensing, "正在出货..."},
            { States.OutOfStock, "商品已售罄"}
        };

        /// <summary>
        /// 构造函数初始化自动售货机状态机。
        /// </summary>
        public VendingMachine()
        {
            _machine = new StateMachine<States, Triggers>(States.Idle);

            ConfigureStateMachine(); // 配置状态机的行为和状态转换。
        }

        /// <summary>
        /// 配置状态机的状态转换规则和相关行为。
        /// </summary>
        private void ConfigureStateMachine()
        {
            _machine.Configure(States.Idle)
                .Permit(Triggers.InsertCoin, States.HasCoin);

            _machine.Configure(States.HasCoin)
                .OnEntry(() => Console.WriteLine(_stateMessages[States.HasCoin])) // 进入状态时打印消息。
                .Permit(Triggers.EjectCoin, States.Dispensing);

            _machine.Configure(States.Dispensing)
                .OnEntry(() =>
                {
                    Console.WriteLine(_stateMessages[States.Dispensing]);
                    TryDispense(); // 尝试出货。
                })
                .Permit(Triggers.Dispense, States.OutOfStock);

            _machine.Configure(States.OutOfStock)
                .OnEntry(() => Console.WriteLine(_stateMessages[States.OutOfStock])) // 进入售罄状态时打印消息。
                .Permit(Triggers.Refill, States.Idle);
        }

        public void TryDispense()
        {
            try
            {
                Console.WriteLine("出货中...");
                _machine.Fire(Triggers.Dispense); // 从Dispensing状态转换回Idle
            }
            catch (Exception ex)
            {
                Console.WriteLine("出货失败: " + ex.Message);
            }
        }


        /// <summary>
        /// 用户插入硬币触发的状态转换。
        /// </summary>
        public void InsertCoin()
        {
            _machine.Fire(Triggers.InsertCoin);
        }

        /// <summary>
        /// 用户请求退币触发的状态转换。
        /// </summary>
        public void EjectCoin()
        {
            _machine.Fire(Triggers.EjectCoin);
        }

        /// <summary>
        /// 用户请求出货，如果状态允许则触发状态转换。
        /// </summary>
        public void Dispense()
        {
            if (_machine.State == States.HasCoin)
            {
                _machine.Fire(Triggers.Dispense);
            }
            else
            {
                Console.WriteLine("无法出货，当前状态不允许");
            }
        }

        /// <summary>
        /// 用户请求补货，如果状态允许则触发状态转换。
        /// </summary>
        public void Refill()
        {
            if (_machine.State == States.OutOfStock)
            {
                _machine.Fire(Triggers.Refill);
            }
            else
            {
                Console.WriteLine("无需补货，当前状态正常");
            }
        }
    }
}
